/* x86_SSE2.h
 * 
 *  Author          : Alexander J. Yee
 *  Date Created    : 09/03/2014
 *  Last Modified   : 09/03/2014
 * 
 */

#pragma once
#ifndef ymp_ArchSpecific_x86_SSE2_H
#define ymp_ArchSpecific_x86_SSE2_H
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Dependencies
#include <emmintrin.h>
#ifdef _WIN32
// Visual Studio puts _mm_set1_epi64x() in <intrin.h> instead of <emmintrin.h>.
#include <intrin.h>
#endif
#include "PublicLibs/CompilerSettings.h"
#include "PublicLibs/Types.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if !(defined _WIN64) && !(defined __x86_64__)
//static YM_FORCE_INLINE __m128i _mm_set1_epi64x(s64_t x){
//    __m128i a = _mm_set1_epi32((s32_t)x);
//    __m128i b = _mm_set1_epi32((s32_t)(x >> 32));
//    return _mm_unpacklo_epi32(a, b);
//}
static YM_FORCE_INLINE ymp::s64_t _mm_cvtsi128_si64(__m128i x){
    return (ymp::u32_t)_mm_cvtsi128_si32(x) | (ymp::s64_t)_mm_cvtsi128_si32(_mm_shuffle_epi32(x, 177)) << 32;
}
static YM_FORCE_INLINE __m128i _mm_cvtsi64_si128(ymp::s64_t x){
    return _mm_loadl_epi64((const __m128i*)&x);
}
#endif
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
YM_FORCE_INLINE ymp::s64_t _mm_reduce_or_epi64(__m128i x){
    x = _mm_or_si128(x, _mm_unpackhi_epi64(x, x));
    return _mm_cvtsi128_si64(x);
}
YM_FORCE_INLINE ymp::s64_t _mm_reduce_add_epi64(__m128i x){
    x = _mm_add_epi64(x, _mm_unpackhi_epi64(x, x));
    return _mm_cvtsi128_si64(x);
}
YM_FORCE_INLINE double _mm_reduce_add_pd(__m128d x){
    x = _mm_add_pd(x, _mm_unpackhi_pd(x, x));
    return _mm_cvtsd_f64(x);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#endif
